<!DOCTYPE html>
<html>
  <head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
  <meta name="description" content="刘清政">
  <meta name="keyword" content="hexo-theme">
  
    <link rel="shortcut icon" href="/css/images/logo.png">
  
  <title>
    
      go/2-Go语言基础/11-数组和切片 | Justin-刘清政的博客
    
  </title>
  <link href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <link href="//cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.css" rel="stylesheet">
  <link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/tomorrow.min.css" rel="stylesheet">
  
<link rel="stylesheet" href="/css/style.css">

  
    
<link rel="stylesheet" href="/css/plugins/gitment.css">

  
  <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/geopattern/1.2.3/js/geopattern.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.js"></script>
  
    
<script src="/js/qrious.js"></script>

  
  
    
<script src="/js/gitment.js"></script>

  
  

  
<meta name="generator" content="Hexo 4.2.0"></head>
<div class="wechat-share">
  <img src="/css/images/logo.png" />
</div>

  <body>
    <header class="header fixed-header">
  <div class="header-container">
    <a class="home-link" href="/">
      <div class="logo"></div>
      <span>Justin-刘清政的博客</span>
    </a>
    <ul class="right-list">
      
        <li class="list-item">
          
            <a href="/" class="item-link">主页</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/tags/" class="item-link">标签</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/archives/" class="item-link">归档</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/about/" class="item-link">关于我</a>
          
        </li>
      
    </ul>
    <div class="menu">
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
    </div>
    <div class="menu-mask">
      <ul class="menu-list">
        
          <li class="menu-item">
            
              <a href="/" class="menu-link">主页</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/tags/" class="menu-link">标签</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/archives/" class="menu-link">归档</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/about/" class="menu-link">关于我</a>
            
          </li>
        
      </ul>
    </div>
  </div>
</header>

    <div id="article-banner">
  <h2>go/2-Go语言基础/11-数组和切片</h2>



  <p class="post-date">2019-02-10</p>
    <!-- 不蒜子统计 -->
    <span id="busuanzi_container_page_pv" style='display:none' class="">
        <i class="icon-smile icon"></i> 阅读数：<span id="busuanzi_value_page_pv"></span>次
    </span>
  <div class="arrow-down">
    <a href="javascript:;"></a>
  </div>
</div>
<main class="app-body flex-box">
  <!-- Article START -->
  <article class="post-article">
    <section class="markdown-content"><hr>
<p>title: “11-数组和切片”<br>date: 2019-03-10 08:08<br>tags:</p>
<ul>
<li>Go</li>
</ul>
<hr>
<h2 id="数组"><a href="#数组" class="headerlink" title="数组"></a>数组</h2><p>数组是同一类型元素的集合。例如，整数集合 5,8,9,79,76 形成一个数组。Go 语言中不允许混合不同类型的元素，例如包含字符串和整数的数组。（当然，如果是 interface{} 类型数组，可以包含任意类型）</p>
<h3 id="数组的声明"><a href="#数组的声明" class="headerlink" title="数组的声明"></a>数组的声明</h3><p>一个数组的表示形式为 <code>[n]T</code>。<code>n</code> 表示数组中元素的数量，<code>T</code> 代表每个元素的类型。元素的数量 <code>n</code> 也是该类型的一部分（稍后我们将详细讨论这一点）。</p>
<p>可以使用不同的方式来声明数组，让我们一个一个的来看。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    <span class="keyword">var</span> a [<span class="number">3</span>]<span class="keyword">int</span> <span class="comment">//int array with length 3</span></span><br><span class="line">    fmt.Println(a)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>var a[3]int</strong> 声明了一个长度为 3 的整型数组。<strong>数组中的所有元素都被自动赋值为数组类型的零值。</strong> 在这种情况下，<code>a</code> 是一个整型数组，因此 <code>a</code> 的所有元素都被赋值为 <code>0</code>，即 int 型的零值。运行上述程序将 <strong>输出</strong> <code>[0 0 0]</code>。</p>
<p>数组的索引从 <code>0</code> 开始到 <code>length - 1</code> 结束。让我们给上面的数组赋值。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    <span class="keyword">var</span> a [<span class="number">3</span>]<span class="keyword">int</span> <span class="comment">//int array with length 3</span></span><br><span class="line">    a[<span class="number">0</span>] = <span class="number">12</span> <span class="comment">// array index starts at 0</span></span><br><span class="line">    a[<span class="number">1</span>] = <span class="number">78</span></span><br><span class="line">    a[<span class="number">2</span>] = <span class="number">50</span></span><br><span class="line">    fmt.Println(a)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>a[0] 将值赋给数组的第一个元素。该程序将 <strong>输出</strong> <code>[12 78 50]</code>。</p>
<p>让我们使用 <strong>简略声明</strong> 来创建相同的数组。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    a := [<span class="number">3</span>]<span class="keyword">int</span>&#123;<span class="number">12</span>, <span class="number">78</span>, <span class="number">50</span>&#125; <span class="comment">// short hand declaration to create array</span></span><br><span class="line">    fmt.Println(a)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>上面的程序将会打印相同的 <strong>输出</strong> <code>[12 78 50]</code>。</p>
<p>在简略声明中，不需要将数组中所有的元素赋值。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    a := [<span class="number">3</span>]<span class="keyword">int</span>&#123;<span class="number">12</span>&#125; </span><br><span class="line">    fmt.Println(a)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上述程序中的第 8 行 <code>a := [3]int{12}</code> 声明一个长度为 3 的数组，但只提供了一个值 <code>12</code>，剩下的 2 个元素自动赋值为 <code>0</code>。这个程序将<strong>输出</strong> <code>[12 0 0]</code>。</p>
<p>你甚至可以忽略声明数组的长度，并用 <code>...</code> 代替，让编译器为你自动计算长度，这在下面的程序中实现。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    a := [...]<span class="keyword">int</span>&#123;<span class="number">12</span>, <span class="number">78</span>, <span class="number">50</span>&#125; <span class="comment">// ... makes the compiler determine the length</span></span><br><span class="line">    fmt.Println(a)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>数组的大小是类型的一部分</strong>。因此 <code>[5]int</code> 和 <code>[25]int</code> 是不同类型。数组不能调整大小，不要担心这个限制，因为 <code>slices</code> 的存在能解决这个问题。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    a := [<span class="number">3</span>]<span class="keyword">int</span>&#123;<span class="number">5</span>, <span class="number">78</span>, <span class="number">8</span>&#125;</span><br><span class="line">    <span class="keyword">var</span> b [<span class="number">5</span>]<span class="keyword">int</span></span><br><span class="line">    b = a <span class="comment">// not possible since [3]int and [5]int are distinct types</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上述程序的第 6 行中, 我们试图将类型 <code>[3]int</code> 的变量赋给类型为 <code>[5]int</code> 的变量，这是不允许的，因此编译器将抛出错误 main.go:6: cannot use a (type [3]int) as type [5]int in assignment。</p>
<h3 id="数组是值类型"><a href="#数组是值类型" class="headerlink" title="数组是值类型"></a>数组是值类型</h3><p>Go 中的数组是值类型而不是引用类型。这意味着当数组赋值给一个新的变量时，该变量会得到一个原始数组的一个副本。如果对新变量进行更改，则不会影响原始数组。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">"fmt"</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    a := [...]<span class="keyword">string</span>&#123;<span class="string">"USA"</span>, <span class="string">"China"</span>, <span class="string">"India"</span>, <span class="string">"Germany"</span>, <span class="string">"France"</span>&#125;</span><br><span class="line">    b := a <span class="comment">// a copy of a is assigned to b</span></span><br><span class="line">    b[<span class="number">0</span>] = <span class="string">"Singapore"</span></span><br><span class="line">    fmt.Println(<span class="string">"a is "</span>, a)</span><br><span class="line">    fmt.Println(<span class="string">"b is "</span>, b) </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上述程序的第 7 行，<code>a</code> 的副本被赋给 <code>b</code>。在第 8 行中，<code>b</code> 的第一个元素改为 <code>Singapore</code>。这不会在原始数组 <code>a</code> 中反映出来。该程序将 <strong>输出</strong>,</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">a is [USA China India Germany France]  </span><br><span class="line">b is [Singapore China India Germany France]</span><br></pre></td></tr></table></figure>

<p>同样，当数组作为参数传递给函数时，它们是按值传递，而原始数组保持不变。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">"fmt"</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">changeLocal</span><span class="params">(num [5]<span class="keyword">int</span>)</span></span> &#123;</span><br><span class="line">    num[<span class="number">0</span>] = <span class="number">55</span></span><br><span class="line">    fmt.Println(<span class="string">"inside function "</span>, num)</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    num := [...]<span class="keyword">int</span>&#123;<span class="number">5</span>, <span class="number">6</span>, <span class="number">7</span>, <span class="number">8</span>, <span class="number">8</span>&#125;</span><br><span class="line">    fmt.Println(<span class="string">"before passing to function "</span>, num)</span><br><span class="line">    changeLocal(num) <span class="comment">//num is passed by value</span></span><br><span class="line">    fmt.Println(<span class="string">"after passing to function "</span>, num)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上述程序的 13 行中, 数组 <code>num</code> 实际上是通过值传递给函数 <code>changeLocal</code>，数组不会因为函数调用而改变。这个程序将输出,</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">before passing to function  [5 6 7 8 8]</span><br><span class="line">inside function  [55 6 7 8 8]</span><br><span class="line">after passing to function  [5 6 7 8 8]</span><br></pre></td></tr></table></figure>

<h3 id="数组的长度"><a href="#数组的长度" class="headerlink" title="数组的长度"></a>数组的长度</h3><p>通过将数组作为参数传递给 <code>len</code> 函数，可以得到数组的长度。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">"fmt"</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    a := [...]<span class="keyword">float64</span>&#123;<span class="number">67.7</span>, <span class="number">89.8</span>, <span class="number">21</span>, <span class="number">78</span>&#125;</span><br><span class="line">    fmt.Println(<span class="string">"length of a is"</span>,<span class="built_in">len</span>(a))</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>上面的程序输出为 <code>length of a is 4</code>。</p>
<h3 id="使用-range-迭代数组"><a href="#使用-range-迭代数组" class="headerlink" title="使用 range 迭代数组"></a>使用 range 迭代数组</h3><p><code>for</code> 循环可用于遍历数组中的元素。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">"fmt"</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    a := [...]<span class="keyword">float64</span>&#123;<span class="number">67.7</span>, <span class="number">89.8</span>, <span class="number">21</span>, <span class="number">78</span>&#125;</span><br><span class="line">    <span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="built_in">len</span>(a); i++ &#123; <span class="comment">// looping from 0 to the length of the array</span></span><br><span class="line">        fmt.Printf(<span class="string">"%d th element of a is %.2f\n"</span>, i, a[i])</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>上面的程序使用 <code>for</code> 循环遍历数组中的元素，从索引 <code>0</code> 到 <code>length of the array - 1</code>。这个程序运行后打印出，</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">0 th element of a is 67.70  </span><br><span class="line">1 th element of a is 89.80  </span><br><span class="line">2 th element of a is 21.00  </span><br><span class="line">3 th element of a is 78.00</span><br></pre></td></tr></table></figure>

<p>Go 提供了一种更好、更简洁的方法，通过使用 <code>for</code> 循环的 <strong>range</strong> 方法来遍历数组。<code>range</code> 返回索引和该索引处的值。让我们使用 range 重写上面的代码。我们还可以获取数组中所有元素的总和。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">"fmt"</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    a := [...]<span class="keyword">float64</span>&#123;<span class="number">67.7</span>, <span class="number">89.8</span>, <span class="number">21</span>, <span class="number">78</span>&#125;</span><br><span class="line">    sum := <span class="keyword">float64</span>(<span class="number">0</span>)</span><br><span class="line">    <span class="keyword">for</span> i, v := <span class="keyword">range</span> a &#123;<span class="comment">//range returns both the index and value</span></span><br><span class="line">        fmt.Printf(<span class="string">"%d the element of a is %.2f\n"</span>, i, v)</span><br><span class="line">        sum += v</span><br><span class="line">    &#125;</span><br><span class="line">    fmt.Println(<span class="string">"\nsum of all elements of a"</span>,sum)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>上述程序的第 8 行 <code>for i, v := range a</code> 利用的是 for 循环 range 方式。 它将返回索引和该索引处的值。 我们打印这些值，并计算数组 <code>a</code> 中所有元素的总和。 程序的 <strong>输出是</strong>，</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">0 the element of a is 67.70</span><br><span class="line">1 the element of a is 89.80</span><br><span class="line">2 the element of a is 21.00</span><br><span class="line">3 the element of a is 78.00</span><br><span class="line"></span><br><span class="line">sum of all elements of a 256.5</span><br></pre></td></tr></table></figure>

<p>如果你只需要值并希望忽略索引，则可以通过用 <code>_</code> 空白标识符替换索引来执行。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> _, v := <span class="keyword">range</span> a &#123; <span class="comment">// ignores index  </span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>上面的 for 循环忽略索引，同样值也可以被忽略。</p>
<h3 id="多维数组"><a href="#多维数组" class="headerlink" title="多维数组"></a>多维数组</h3><p>到目前为止我们创建的数组都是一维的，Go 语言可以创建多维数组。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">printarray</span><span class="params">(a [3][2]<span class="keyword">string</span>)</span></span> &#123;</span><br><span class="line">    <span class="keyword">for</span> _, v1 := <span class="keyword">range</span> a &#123;</span><br><span class="line">        <span class="keyword">for</span> _, v2 := <span class="keyword">range</span> v1 &#123;</span><br><span class="line">            fmt.Printf(<span class="string">"%s "</span>, v2)</span><br><span class="line">        &#125;</span><br><span class="line">        fmt.Printf(<span class="string">"\n"</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    a := [<span class="number">3</span>][<span class="number">2</span>]<span class="keyword">string</span>&#123;</span><br><span class="line">        &#123;<span class="string">"lion"</span>, <span class="string">"tiger"</span>&#125;,</span><br><span class="line">        &#123;<span class="string">"cat"</span>, <span class="string">"dog"</span>&#125;,</span><br><span class="line">        &#123;<span class="string">"pigeon"</span>, <span class="string">"peacock"</span>&#125;, <span class="comment">// this comma is necessary. The compiler will complain if you omit this comma</span></span><br><span class="line">    &#125;</span><br><span class="line">    printarray(a)</span><br><span class="line">    <span class="keyword">var</span> b [<span class="number">3</span>][<span class="number">2</span>]<span class="keyword">string</span></span><br><span class="line">    b[<span class="number">0</span>][<span class="number">0</span>] = <span class="string">"apple"</span></span><br><span class="line">    b[<span class="number">0</span>][<span class="number">1</span>] = <span class="string">"samsung"</span></span><br><span class="line">    b[<span class="number">1</span>][<span class="number">0</span>] = <span class="string">"microsoft"</span></span><br><span class="line">    b[<span class="number">1</span>][<span class="number">1</span>] = <span class="string">"google"</span></span><br><span class="line">    b[<span class="number">2</span>][<span class="number">0</span>] = <span class="string">"AT&amp;T"</span></span><br><span class="line">    b[<span class="number">2</span>][<span class="number">1</span>] = <span class="string">"T-Mobile"</span></span><br><span class="line">    fmt.Printf(<span class="string">"\n"</span>)</span><br><span class="line">    printarray(b)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上述程序的第 17 行，用简略语法声明一个二维字符串数组 a 。20 行末尾的逗号是必需的。这是因为根据 Go 语言的规则自动插入分号。至于为什么这是必要的，如果你想了解更多，请阅读<a href="https://golang.org/doc/effective_go.html#semicolons" target="_blank" rel="noopener">https://golang.org/doc/effective_go.html#semicolons</a>。</p>
<p>另外一个二维数组 b 在 23 行声明，字符串通过每个索引一个一个添加。这是另一种初始化二维数组的方法。</p>
<p>第 7 行的 printarray 函数使用两个 range 循环来打印二维数组的内容。上述程序的 <strong>输出是</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">lion tiger</span><br><span class="line">cat dog</span><br><span class="line">pigeon peacock</span><br><span class="line"></span><br><span class="line">apple samsung</span><br><span class="line">microsoft google</span><br><span class="line">AT&amp;T T-Mobile</span><br></pre></td></tr></table></figure>

<p>这就是数组，尽管数组看上去似乎足够灵活，但是它们具有固定长度的限制，不可能增加数组的长度。这就要用到 <strong>切片</strong> 了。事实上，在 Go 中，切片比传统数组更常见。</p>
<h2 id="切片"><a href="#切片" class="headerlink" title="切片"></a>切片</h2><p>切片是由数组建立的一种方便、灵活且功能强大的包装（Wrapper）。切片本身不拥有任何数据。它们只是对现有数组的引用。</p>
<h3 id="创建一个切片"><a href="#创建一个切片" class="headerlink" title="创建一个切片"></a>创建一个切片</h3><p>带有 T 类型元素的切片由 <code>[]T</code> 表示</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    a := [<span class="number">5</span>]<span class="keyword">int</span>&#123;<span class="number">76</span>, <span class="number">77</span>, <span class="number">78</span>, <span class="number">79</span>, <span class="number">80</span>&#125;</span><br><span class="line">    <span class="keyword">var</span> b []<span class="keyword">int</span> = a[<span class="number">1</span>:<span class="number">4</span>] <span class="comment">// creates a slice from a[1] to a[3]</span></span><br><span class="line">    fmt.Println(b)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>使用语法 <code>a[start:end]</code> 创建一个从 <code>a</code> 数组索引 <code>start</code> 开始到 <code>end - 1</code> 结束的切片。因此，在上述程序的第 9 行中, <code>a[1:4]</code> 从索引 1 到 3 创建了 <code>a</code> 数组的一个切片表示。因此, 切片 <code>b</code> 的值为 <code>[77 78 79]</code>。</p>
<p>让我们看看另一种创建切片的方法。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (  </span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;  </span><br><span class="line">    c := []<span class="keyword">int</span>&#123;<span class="number">6</span>, <span class="number">7</span>, <span class="number">8</span>&#125; <span class="comment">// creates and array and returns a slice reference</span></span><br><span class="line">    fmt.Println(c)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上述程序的第 9 行，<code>c：= [] int {6，7，8}</code> 创建一个有 3 个整型元素的数组，并返回一个存储在 c 中的切片引用。</p>
<h3 id="切片的修改"><a href="#切片的修改" class="headerlink" title="切片的修改"></a>切片的修改</h3><p>切片自己不拥有任何数据。它只是底层数组的一种表示。对切片所做的任何修改都会反映在底层数组中。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    darr := [...]<span class="keyword">int</span>&#123;<span class="number">57</span>, <span class="number">89</span>, <span class="number">90</span>, <span class="number">82</span>, <span class="number">100</span>, <span class="number">78</span>, <span class="number">67</span>, <span class="number">69</span>, <span class="number">59</span>&#125;</span><br><span class="line">    dslice := darr[<span class="number">2</span>:<span class="number">5</span>]</span><br><span class="line">    fmt.Println(<span class="string">"array before"</span>, darr)</span><br><span class="line">    <span class="keyword">for</span> i := <span class="keyword">range</span> dslice &#123;</span><br><span class="line">        dslice[i]++</span><br><span class="line">    &#125;</span><br><span class="line">    fmt.Println(<span class="string">"array after"</span>, darr)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上述程序的第 9 行，我们根据数组索引 2,3,4 创建一个切片 <code>dslice</code>。for 循环将这些索引中的值逐个递增。当我们使用 for 循环打印数组时，我们可以看到对切片的更改反映在数组中。该程序的输出是</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">array before [57 89 90 82 100 78 67 69 59]  </span><br><span class="line">array after [57 89 91 83 101 78 67 69 59]</span><br></pre></td></tr></table></figure>

<p>当多个切片共用相同的底层数组时，每个切片所做的更改将反映在数组中。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    numa := [<span class="number">3</span>]<span class="keyword">int</span>&#123;<span class="number">78</span>, <span class="number">79</span> ,<span class="number">80</span>&#125;</span><br><span class="line">    nums1 := numa[:] <span class="comment">// creates a slice which contains all elements of the array</span></span><br><span class="line">    nums2 := numa[:]</span><br><span class="line">    fmt.Println(<span class="string">"array before change 1"</span>, numa)</span><br><span class="line">    nums1[<span class="number">0</span>] = <span class="number">100</span></span><br><span class="line">    fmt.Println(<span class="string">"array after modification to slice nums1"</span>, numa)</span><br><span class="line">    nums2[<span class="number">1</span>] = <span class="number">101</span></span><br><span class="line">    fmt.Println(<span class="string">"array after modification to slice nums2"</span>, numa)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在 9 行中，<code>numa [:]</code> 缺少开始和结束值。开始和结束的默认值分别为 <code>0</code> 和 <code>len (numa)</code>。两个切片 <code>nums1</code> 和 <code>nums2</code> 共享相同的数组。该程序的输出是</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">array before change 1 [78 79 80]  </span><br><span class="line">array after modification to slice nums1 [100 79 80]  </span><br><span class="line">array after modification to slice nums2 [100 101 80]</span><br></pre></td></tr></table></figure>

<p>从输出中可以清楚地看出，当切片共享同一个数组时，每个所做的修改都会反映在数组中。</p>
<h3 id="切片的长度和容量"><a href="#切片的长度和容量" class="headerlink" title="切片的长度和容量"></a>切片的长度和容量</h3><p>切片的长度是切片中的元素数。<strong>切片的容量是从创建切片索引开始的底层数组中元素数。</strong></p>
<p>让我们写一段代码来更好地理解这点。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    fruitarray := [...]<span class="keyword">string</span>&#123;<span class="string">"apple"</span>, <span class="string">"orange"</span>, <span class="string">"grape"</span>, <span class="string">"mango"</span>, <span class="string">"water melon"</span>, <span class="string">"pine apple"</span>, <span class="string">"chikoo"</span>&#125;</span><br><span class="line">    fruitslice := fruitarray[<span class="number">1</span>:<span class="number">3</span>]</span><br><span class="line">    fmt.Printf(<span class="string">"length of slice %d capacity %d"</span>, <span class="built_in">len</span>(fruitslice), <span class="built_in">cap</span>(fruitslice)) <span class="comment">// length of is 2 and capacity is 6</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上面的程序中，<code>fruitslice</code> 是从 <code>fruitarray</code> 的索引 1 和 2 创建的。 因此，<code>fruitlice</code> 的长度为 <code>2</code>。</p>
<p><code>fruitarray</code> 的长度是 7。<code>fruiteslice</code> 是从 <code>fruitarray</code> 的索引 <code>1</code> 创建的。因此, <code>fruitslice</code> 的容量是从 <code>fruitarray</code> 索引为 <code>1</code> 开始，也就是说从 <code>orange</code> 开始，该值是 <code>6</code>。因此, <code>fruitslice</code> 的容量为 6。该[程序]输出切片的 <strong>长度为 2 容量为 6</strong> 。</p>
<p>切片可以重置其容量。任何超出这一点将导致程序运行时抛出错误。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    fruitarray := [...]<span class="keyword">string</span>&#123;<span class="string">"apple"</span>, <span class="string">"orange"</span>, <span class="string">"grape"</span>, <span class="string">"mango"</span>, <span class="string">"water melon"</span>, <span class="string">"pine apple"</span>, <span class="string">"chikoo"</span>&#125;</span><br><span class="line">    fruitslice := fruitarray[<span class="number">1</span>:<span class="number">3</span>]</span><br><span class="line">    fmt.Printf(<span class="string">"length of slice %d capacity %d\n"</span>, <span class="built_in">len</span>(fruitslice), <span class="built_in">cap</span>(fruitslice)) <span class="comment">// length of is 2 and capacity is 6</span></span><br><span class="line">    fruitslice = fruitslice[:<span class="built_in">cap</span>(fruitslice)] <span class="comment">// re-slicing furitslice till its capacity</span></span><br><span class="line">    fmt.Println(<span class="string">"After re-slicing length is"</span>,<span class="built_in">len</span>(fruitslice), <span class="string">"and capacity is"</span>,<span class="built_in">cap</span>(fruitslice))</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上述程序的第 11 行中，<code>fruitslice</code> 的容量是重置的。以上程序输出为，</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">length of slice 2 capacity 6 </span><br><span class="line">After re-slicing length is 6 and capacity is 6</span><br></pre></td></tr></table></figure>

<h3 id="使用-make-创建一个切片"><a href="#使用-make-创建一个切片" class="headerlink" title="使用 make 创建一个切片"></a>使用 make 创建一个切片</h3><p>func make（[]T，len，cap）[]T 通过传递类型，长度和容量来创建切片。容量是可选参数, 默认值为切片长度。make 函数创建一个数组，并返回引用该数组的切片。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    i := <span class="built_in">make</span>([]<span class="keyword">int</span>, <span class="number">5</span>, <span class="number">5</span>)</span><br><span class="line">    fmt.Println(i)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>使用 make 创建切片时默认情况下这些值为零。上述程序的输出为 <code>[0 0 0 0 0]</code>。</p>
<h3 id="追加切片元素"><a href="#追加切片元素" class="headerlink" title="追加切片元素"></a>追加切片元素</h3><p>正如我们已经知道数组的长度是固定的，它的长度不能增加。 切片是动态的，使用 <code>append</code> 可以将新元素追加到切片上。append 函数的定义是 <code>func append（s[]T，x ... T）[]T</code>。</p>
<p><strong>x … T</strong> 在函数定义中表示该函数接受参数 x 的个数是可变的。这些类型的函数被称为[可变函数]。</p>
<p>有一个问题可能会困扰你。如果切片由数组支持，并且数组本身的长度是固定的，那么切片如何具有动态长度。以及内部发生了什么，当新的元素被添加到切片时，会创建一个新的数组。现有数组的元素被复制到这个新数组中，并返回这个新数组的新切片引用。现在新切片的容量是旧切片的两倍。下面的程序会让你清晰理解。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    cars := []<span class="keyword">string</span>&#123;<span class="string">"Ferrari"</span>, <span class="string">"Honda"</span>, <span class="string">"Ford"</span>&#125;</span><br><span class="line">    fmt.Println(<span class="string">"cars:"</span>, cars, <span class="string">"has old length"</span>, <span class="built_in">len</span>(cars), <span class="string">"and capacity"</span>, <span class="built_in">cap</span>(cars)) <span class="comment">// capacity of cars is 3</span></span><br><span class="line">    cars = <span class="built_in">append</span>(cars, <span class="string">"Toyota"</span>)</span><br><span class="line">    fmt.Println(<span class="string">"cars:"</span>, cars, <span class="string">"has new length"</span>, <span class="built_in">len</span>(cars), <span class="string">"and capacity"</span>, <span class="built_in">cap</span>(cars)) <span class="comment">// capacity of cars is doubled to 6</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上述程序中，<code>cars</code> 的容量最初是 3。在第 10 行，我们给 cars 添加了一个新的元素，并把 <code>append(cars, &quot;Toyota&quot;)</code> 返回的切片赋值给 cars。现在 cars 的容量翻了一番，变成了 6。上述程序的输出是</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cars: [Ferrari Honda Ford] has old length 3 and capacity 3  </span><br><span class="line">cars: [Ferrari Honda Ford Toyota] has new length 4 and capacity 6</span><br></pre></td></tr></table></figure>

<p>切片类型的零值为 <code>nil</code>。一个 <code>nil</code> 切片的长度和容量为 0。可以使用 append 函数将值追加到 <code>nil</code> 切片。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (  </span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;  </span><br><span class="line">    <span class="keyword">var</span> names []<span class="keyword">string</span> <span class="comment">//zero value of a slice is nil</span></span><br><span class="line">    <span class="keyword">if</span> names == <span class="literal">nil</span> &#123;</span><br><span class="line">        fmt.Println(<span class="string">"slice is nil going to append"</span>)</span><br><span class="line">        names = <span class="built_in">append</span>(names, <span class="string">"John"</span>, <span class="string">"Sebastian"</span>, <span class="string">"Vinay"</span>)</span><br><span class="line">        fmt.Println(<span class="string">"names contents:"</span>,names)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上面的程序 <code>names</code> 是 nil，我们已经添加 3 个字符串给 <code>names</code>。该程序的输出是</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">slice is nil going to append  </span><br><span class="line">names contents: [John Sebastian Vinay]</span><br></pre></td></tr></table></figure>

<p>也可以使用 <code>...</code> 运算符将一个切片添加到另一个切片。 你可以在[可变参数函数]教程中了解有关此运算符的更多信息。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    veggies := []<span class="keyword">string</span>&#123;<span class="string">"potatoes"</span>, <span class="string">"tomatoes"</span>, <span class="string">"brinjal"</span>&#125;</span><br><span class="line">    fruits := []<span class="keyword">string</span>&#123;<span class="string">"oranges"</span>, <span class="string">"apples"</span>&#125;</span><br><span class="line">    food := <span class="built_in">append</span>(veggies, fruits...)</span><br><span class="line">    fmt.Println(<span class="string">"food:"</span>,food)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上述程序的第 10 行，food 是通过 append(veggies, fruits…) 创建。程序的输出为 <code>food: [potatoes tomatoes brinjal oranges apples]</code>。</p>
<h3 id="切片的函数传递"><a href="#切片的函数传递" class="headerlink" title="切片的函数传递"></a>切片的函数传递</h3><p>我们可以认为，切片在内部可由一个结构体类型表示。这是它的表现形式，</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> slice <span class="keyword">struct</span> &#123;  </span><br><span class="line">    Length        <span class="keyword">int</span></span><br><span class="line">    Capacity      <span class="keyword">int</span></span><br><span class="line">    ZerothElement *<span class="keyword">byte</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>切片包含长度、容量和指向数组第零个元素的指针。当切片传递给函数时，即使它通过值传递，指针变量也将引用相同的底层数组。因此，当切片作为参数传递给函数时，函数内所做的更改也会在函数外可见。让我们写一个程序来检查这点。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">subtactOne</span><span class="params">(numbers []<span class="keyword">int</span>)</span></span> &#123;</span><br><span class="line">    <span class="keyword">for</span> i := <span class="keyword">range</span> numbers &#123;</span><br><span class="line">        numbers[i] -= <span class="number">2</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    nos := []<span class="keyword">int</span>&#123;<span class="number">8</span>, <span class="number">7</span>, <span class="number">6</span>&#125;</span><br><span class="line">    fmt.Println(<span class="string">"slice before function call"</span>, nos)</span><br><span class="line">    subtactOne(nos)                               <span class="comment">// function modifies the slice</span></span><br><span class="line">    fmt.Println(<span class="string">"slice after function call"</span>, nos) <span class="comment">// modifications are visible outside</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>上述程序的行号 17 中，调用函数将切片中的每个元素递减 2。在函数调用后打印切片时，这些更改是可见的。如果你还记得，这是不同于数组的，对于函数中一个数组的变化在函数外是不可见的。上述[程序]的输出是，</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">array before function call [8 7 6]  </span><br><span class="line">array after function call [6 5 4]</span><br></pre></td></tr></table></figure>

<h3 id="多维切片"><a href="#多维切片" class="headerlink" title="多维切片"></a>多维切片</h3><p>类似于数组，切片可以有多个维度。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;  </span><br><span class="line">     pls := [][]<span class="keyword">string</span> &#123;</span><br><span class="line">            &#123;<span class="string">"C"</span>, <span class="string">"C++"</span>&#125;,</span><br><span class="line">            &#123;<span class="string">"JavaScript"</span>&#125;,</span><br><span class="line">            &#123;<span class="string">"Go"</span>, <span class="string">"Rust"</span>&#125;,</span><br><span class="line">            &#125;</span><br><span class="line">    <span class="keyword">for</span> _, v1 := <span class="keyword">range</span> pls &#123;</span><br><span class="line">        <span class="keyword">for</span> _, v2 := <span class="keyword">range</span> v1 &#123;</span><br><span class="line">            fmt.Printf(<span class="string">"%s "</span>, v2)</span><br><span class="line">        &#125;</span><br><span class="line">        fmt.Printf(<span class="string">"\n"</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>程序的输出为，</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">C C++  </span><br><span class="line">JavaScript  </span><br><span class="line">Go Rust</span><br></pre></td></tr></table></figure>

<h3 id="内存优化"><a href="#内存优化" class="headerlink" title="内存优化"></a>内存优化</h3><p>切片持有对底层数组的引用。只要切片在内存中，数组就不能被垃圾回收。在内存管理方面，这是需要注意的。让我们假设我们有一个非常大的数组，我们只想处理它的一小部分。然后，我们由这个数组创建一个切片，并开始处理切片。这里需要重点注意的是，在切片引用时数组仍然存在内存中。</p>
<p>一种解决方法是使用 [copy] 函数 <code>func copy(dst，src[]T)int</code> 来生成一个切片的副本。这样我们可以使用新的切片，原始数组可以被垃圾回收。</p>
<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line">    <span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">countries</span><span class="params">()</span> []<span class="title">string</span></span> &#123;</span><br><span class="line">    countries := []<span class="keyword">string</span>&#123;<span class="string">"USA"</span>, <span class="string">"Singapore"</span>, <span class="string">"Germany"</span>, <span class="string">"India"</span>, <span class="string">"Australia"</span>&#125;</span><br><span class="line">    neededCountries := countries[:<span class="built_in">len</span>(countries)<span class="number">-2</span>]</span><br><span class="line">    countriesCpy := <span class="built_in">make</span>([]<span class="keyword">string</span>, <span class="built_in">len</span>(neededCountries))</span><br><span class="line">    <span class="built_in">copy</span>(countriesCpy, neededCountries) <span class="comment">//copies neededCountries to countriesCpy</span></span><br><span class="line">    <span class="keyword">return</span> countriesCpy</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    countriesNeeded := countries()</span><br><span class="line">    fmt.Println(countriesNeeded)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上述程序的第 9 行，<code>neededCountries := countries[:len(countries)-2</code> 创建一个去掉尾部 2 个元素的切片 <code>countries</code>，在上述程序的 11 行，将 <code>neededCountries</code> 复制到 <code>countriesCpy</code> 同时在函数的下一行返回 countriesCpy。现在 <code>countries</code> 数组可以被垃圾回收, 因为 <code>neededCountries</code> 不再被引用。</p>
</section>
    <!-- Tags START -->
    
    <!-- Tags END -->
    <!-- NAV START -->
    
  <div class="nav-container">
    <!-- reverse left and right to put prev and next in a more logic postition -->
    
      <a class="nav-left" href="/go/2-Go%E8%AF%AD%E8%A8%80%E5%9F%BA%E7%A1%80/24-Select/">
        <span class="nav-arrow">← </span>
        
          go/2-Go语言基础/24-Select
        
      </a>
    
    
      <a class="nav-right" href="/go/2-Go%E8%AF%AD%E8%A8%80%E5%9F%BA%E7%A1%80/27-%E7%BB%84%E5%90%88%E5%8F%96%E4%BB%A3%E7%BB%A7%E6%89%BF/">
        
          go/2-Go语言基础/27-组合取代继承
        
        <span class="nav-arrow"> →</span>
      </a>
    
  </div>

    <!-- NAV END -->
    <!-- 打赏 START -->
    
      <div class="money-like">
        <div class="reward-btn">
          赏
          <span class="money-code">
            <span class="alipay-code">
              <div class="code-image"></div>
              <b>使用支付宝打赏</b>
            </span>
            <span class="wechat-code">
              <div class="code-image"></div>
              <b>使用微信打赏</b>
            </span>
          </span>
        </div>
        <p class="notice">点击上方按钮,请我喝杯咖啡！</p>
      </div>
    
    <!-- 打赏 END -->
    <!-- 二维码 START -->
    
      <div class="qrcode">
        <canvas id="share-qrcode"></canvas>
        <p class="notice">扫描二维码，分享此文章</p>
      </div>
    
    <!-- 二维码 END -->
    
      <!-- Gitment START -->
      <div id="comments"></div>
      <!-- Gitment END -->
    
  </article>
  <!-- Article END -->
  <!-- Catalog START -->
  
    <aside class="catalog-container">
  <div class="toc-main">
  <!-- 不蒜子统计 -->
    <strong class="toc-title">目录</strong>
    
      <ol class="toc-nav"><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#数组"><span class="toc-nav-text">数组</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#数组的声明"><span class="toc-nav-text">数组的声明</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#数组是值类型"><span class="toc-nav-text">数组是值类型</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#数组的长度"><span class="toc-nav-text">数组的长度</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#使用-range-迭代数组"><span class="toc-nav-text">使用 range 迭代数组</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#多维数组"><span class="toc-nav-text">多维数组</span></a></li></ol></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#切片"><span class="toc-nav-text">切片</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#创建一个切片"><span class="toc-nav-text">创建一个切片</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#切片的修改"><span class="toc-nav-text">切片的修改</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#切片的长度和容量"><span class="toc-nav-text">切片的长度和容量</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#使用-make-创建一个切片"><span class="toc-nav-text">使用 make 创建一个切片</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#追加切片元素"><span class="toc-nav-text">追加切片元素</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#切片的函数传递"><span class="toc-nav-text">切片的函数传递</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#多维切片"><span class="toc-nav-text">多维切片</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#内存优化"><span class="toc-nav-text">内存优化</span></a></li></ol></li></ol>
    
  </div>
</aside>
  
  <!-- Catalog END -->
</main>

<script>
  (function () {
    var url = 'http://www.liuqingzheng.top/go/2-Go语言基础/11-数组和切片/';
    var banner = ''
    if (banner !== '' && banner !== 'undefined' && banner !== 'null') {
      $('#article-banner').css({
        'background-image': 'url(' + banner + ')'
      })
    } else {
      $('#article-banner').geopattern(url)
    }
    $('.header').removeClass('fixed-header')

    // error image
    $(".markdown-content img").on('error', function() {
      $(this).attr('src', 'http://file.muyutech.com/error-img.png')
      $(this).css({
        'cursor': 'default'
      })
    })

    // zoom image
    $(".markdown-content img").on('click', function() {
      var src = $(this).attr('src')
      if (src !== 'http://file.muyutech.com/error-img.png') {
        var imageW = $(this).width()
        var imageH = $(this).height()

        var zoom = ($(window).width() * 0.95 / imageW).toFixed(2)
        zoom = zoom < 1 ? 1 : zoom
        zoom = zoom > 2 ? 2 : zoom
        var transY = (($(window).height() - imageH) / 2).toFixed(2)

        $('body').append('<div class="image-view-wrap"><div class="image-view-inner"><img src="'+ src +'" /></div></div>')
        $('.image-view-wrap').addClass('wrap-active')
        $('.image-view-wrap img').css({
          'width': `${imageW}`,
          'transform': `translate3d(0, ${transY}px, 0) scale3d(${zoom}, ${zoom}, 1)`
        })
        $('html').css('overflow', 'hidden')

        $('.image-view-wrap').on('click', function() {
          $(this).remove()
          $('html').attr('style', '')
        })
      }
    })
  })();
</script>


  <script>
    var qr = new QRious({
      element: document.getElementById('share-qrcode'),
      value: document.location.href
    });
  </script>



  <script>
    var gitmentConfig = "liuqingzheng";
    if (gitmentConfig !== 'undefined') {
      var gitment = new Gitment({
        id: "go/2-Go语言基础/11-数组和切片",
        owner: "liuqingzheng",
        repo: "FuckBlog",
        oauth: {
          client_id: "32a4076431cf39d0ecea",
          client_secret: "94484bd79b3346a949acb2fda3c8a76ce16990c6"
        },
        theme: {
          render(state, instance) {
            const container = document.createElement('div')
            container.lang = "en-US"
            container.className = 'gitment-container gitment-root-container'
            container.appendChild(instance.renderHeader(state, instance))
            container.appendChild(instance.renderEditor(state, instance))
            container.appendChild(instance.renderComments(state, instance))
            container.appendChild(instance.renderFooter(state, instance))
            return container;
          }
        }
      })
      gitment.render(document.getElementById('comments'))
    }
  </script>




    <div class="scroll-top">
  <span class="arrow-icon"></span>
</div>
    <footer class="app-footer">
<!-- 不蒜子统计 -->
<span id="busuanzi_container_site_pv">
     本站总访问量<span id="busuanzi_value_site_pv"></span>次
</span>
<span class="post-meta-divider">|</span>
<span id="busuanzi_container_site_uv" style='display:none'>
     本站访客数<span id="busuanzi_value_site_uv"></span>人
</span>
<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>



  <p class="copyright">
    &copy; 2021 | Proudly powered by <a href="https://www.cnblogs.com/xiaoyuanqujing" target="_blank">小猿取经</a>
    <br>
    Theme by <a href="https://www.cnblogs.com/xiaoyuanqujing" target="_blank" rel="noopener">小猿取经</a>
  </p>
</footer>

<script>
  function async(u, c) {
    var d = document, t = 'script',
      o = d.createElement(t),
      s = d.getElementsByTagName(t)[0];
    o.src = u;
    if (c) { o.addEventListener('load', function (e) { c(null, e); }, false); }
    s.parentNode.insertBefore(o, s);
  }
</script>
<script>
  async("//cdnjs.cloudflare.com/ajax/libs/fastclick/1.0.6/fastclick.min.js", function(){
    FastClick.attach(document.body);
  })
</script>

<script>
  var hasLine = 'true';
  async("//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js", function(){
    $('figure pre').each(function(i, block) {
      var figure = $(this).parents('figure');
      if (hasLine === 'false') {
        figure.find('.gutter').hide();
      }
      var lang = figure.attr('class').split(' ')[1] || 'code';
      var codeHtml = $(this).html();
      var codeTag = document.createElement('code');
      codeTag.className = lang;
      codeTag.innerHTML = codeHtml;
      $(this).attr('class', '').empty().html(codeTag);
      figure.attr('data-lang', lang.toUpperCase());
      hljs.highlightBlock(block);
    });
  })
</script>





<!-- Baidu Tongji -->

<script>
    var _baId = 'c5fd96eee1193585be191f318c3fa725';
    // Originial
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "//hm.baidu.com/hm.js?" + _baId;
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
</script>


<script src="/js/script.js"></script>


<script src="/js/search.js"></script>


<script src="/js/load.js"></script>



  <span class="local-search local-search-google local-search-plugin" style="right: 50px;top: 70px;;position:absolute;z-index:2;">
      <input type="search" placeholder="站内搜索" id="local-search-input" class="local-search-input-cls" style="">
      <div id="local-search-result" class="local-search-result-cls"></div>
  </span>


  </body>
</html>